use std::error::Error as StdError;
use std::fmt::Display;
use std::io;
use sqlx::Error as SqlxError;
use redis::RedisError as RedisError;
use serde_json::Error as SerdeJsonError;

pub type Result<T, E = Error> = ::std::result::Result<T, E>;
pub type BoxDynError = Box<dyn StdError + 'static + Send + Sync>;

/// Represents all the ways a method can fail within SQLx.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
    /// Error occurred while parsing a connection string.
    #[error("error with connect: {0}")]
    Connect(String),
    #[error("redis error with : {0}")]
    Redis(#[from] RedisError),
    /// Error occurred while parsing a connection string.
    #[error("error with sqlx: {0}")]
    Sqlx(#[from] SqlxError),

    #[error("error with serde_json: {0}")]
    SerdeJson(#[from] SerdeJsonError),

    #[error("request error with reqwest: {0}")]
    Reqwest(#[from] reqwest::Error),

    /// Error communicating with the database backend.
    #[error("error with io: {0}")]
    Io(#[from] io::Error),

    #[error("config lost: {0}")]
    ConfigLost(String),

    #[error("not support: {0}")]
    NotSupport(String),

    #[error("param lost: {0}")]
    ParamLost(String),
    
    #[error("data not initialize: {0}")]
    DataNotInitialize(String),

    #[error("data is empty: {0}")]
    DataIsEmpty(String),

    #[error("lock error: {0}")]
    LockError(String),

    #[error("get handle error: {0}")]
    HandleError(String),

    /// Error occurred while attempting to establish a TLS connection.
    #[error("common error: {0}")]
    Common(String),

       /// Error occurred while decoding a value from a specific column.
    #[error("error occurred while decoding column {index}: {source}")]
    ColumnDecode {
        index: String,

        #[source]
        source: BoxDynError,
    },

    /// Error occurred while decoding a value.
    #[error("parse error: {0}")]
    Parse(String),

    /// Error occurred while decoding a value.
    #[error("error occurred while decoding: {0}")]
    Decode(#[source] BoxDynError),

    /// Error occurred within the `Any` driver mapping to/from the native driver.
    #[error("error in Any driver mapping: {0}")]
    AnyDriverError(#[source] BoxDynError),

    /// A [`Pool::acquire`] timed out due to connections not becoming available or
    /// because another task encountered too many errors while trying to open a new connection.
    ///
    /// [`Pool::acquire`]: crate::pool::Pool::acquire
    #[error("pool timed out while waiting for an open connection")]
    PoolTimedOut,

    /// [`Pool::close`] was called while we were waiting in [`Pool::acquire`].
    ///
    /// [`Pool::acquire`]: crate::pool::Pool::acquire
    /// [`Pool::close`]: crate::pool::Pool::close
    #[error("attempted to acquire a connection on a closed pool")]
    PoolClosed,

    /// A background worker has crashed.
    #[error("attempted to communicate with a crashed background worker")]
    WorkerCrashed,
}


impl Error {

    #[doc(hidden)]
    #[inline]
    pub fn data_is_empty(err: impl Display) -> Self {
        Error::DataIsEmpty(err.to_string())
    }

    #[doc(hidden)]
    #[inline]
    pub fn config_lost(err: impl Display) -> Self {
        Error::ConfigLost(err.to_string())
    }

    #[doc(hidden)]
    #[inline]
    pub fn decode(err: impl Into<Box<dyn StdError + Send + Sync + 'static>>) -> Self {
        Error::Decode(err.into())
    }
}


// impl From<SqlxError> for Error
// {
//     #[inline]
//     fn from(error: SqlxError) -> Self {
//         Error::Sqlx(error)
//     }
// }
